package falcon.client;

import java.util.Calendar;

import falcon.client.FalconClient.Callback;
import falcon.common.Errno;
import falcon.common.FalconHost;
import falcon.common.Log;
import falcon.common.Md5;
import falcon.protocol.Packet;
import falcon.protocol.PacketFactory;
import falcon.protocol.impl.AckPacket;
import falcon.protocol.impl.BashPacket;
import falcon.protocol.impl.HostPacket;
import falcon.protocol.impl.SysPacket;

public final class FalconClientProxy {
	
	// 默认永不过期
	public static final int NEVER_EXPIRE = -1;
	// 对于登录等简单操作，过期时间设为几秒内即可
	public static final int SIMPLE_EXPIRE = 10000;

	public static class ProxyCallback implements FalconClient.Callback {
		
		public int errno = Errno.NET_RECV_TIMEOUT;
		
		@Override
		public void onComplete(int errno, Packet packet) {
			m_complete = true;
			this.errno = errno;
			m_packet = packet;
		}
		
		public Packet waitFor(int expire) {
			long sleepTime = 25L;
			if (expire < 0) {
				// 对永不过期设置过期时间，防止死循环
				expire = 1000 * 60 * 60 * 24;
				sleepTime = 1000L;
			}
			long start = System.currentTimeMillis();
			while (System.currentTimeMillis() - start < expire) {
				try {
					Thread.sleep(sleepTime);
					if (m_complete) {
						break;
					}
				} catch (Exception e) {
				}
			}
			if (m_packet == null) {
				Log.log("wait expire");
			}
			return m_packet;
		}
		
		private volatile boolean m_complete = false;
		private volatile Packet m_packet = null;
	}

	public FalconClientProxy(FalconClient client) {
		m_client = client;
	}
	
	public int login(String user, String password) {
		SysPacket packet = (SysPacket) PacketFactory.create(PacketFactory.SYS, 0);
		packet.action = SysPacket.Action.LOGIN;
		packet.parameter = String.format("%s\n%s", user, Md5.get(password));
		String info = String.format("login:user=%s", user);
		return waitForSimple(SIMPLE_EXPIRE, info, packet);
	}
	
	public int logout(String user) {
		SysPacket packet = (SysPacket) PacketFactory.create(PacketFactory.SYS, 0);
		packet.action = SysPacket.Action.LOGOUT;
		packet.parameter = String.format("%s", user);
		String info = String.format("logout:user=%s", user);
		return waitForSimple(SIMPLE_EXPIRE, info, packet);
	}
	
	public int addHost(String host, int port, String user, String password) {
		Packet packet = wrapHostPacket(host, port, user, password, HostPacket.Action.ADD);
		String info = String.format("addHost:host=%s;port=%d;user=%s", host, port, user);
		return waitForSimple(SIMPLE_EXPIRE, info, packet);
	}
	
	public int removeHost(String host, int port, String user, String password) {
		Packet packet = wrapHostPacket(host, port, user, password, HostPacket.Action.REMOVE);
		String info = String.format("removeHost:host=%s;port=%d;user=%s", host, port, user);
		return waitForSimple(SIMPLE_EXPIRE, info, packet);
	}
	
	public int execBash(String host, int port, String user, String cmd) {
		return execBash(host, port, user, cmd, NEVER_EXPIRE);
	}
	
	public int execBash(String host, int port, String user, String cmd, int expire) {
		BashPacket packet = (BashPacket) PacketFactory.create(PacketFactory.BASH, 0);
		packet.cmd = cmd;
		packet.host = host;
		packet.port = port;
		packet.user = user;
		String info = String.format("execBash:host=%s;port=%d;user=%s;cmd=%s", host, port, user, cmd);
		return waitForSimple(expire, info, packet);
	}
	
	public void execBash(String host, int port, String user, String cmd, int expire, FalconClient.Callback callback) {
		if (m_client == null) {
			callback.onComplete(Errno.COM_INIT_ERROR, null);
			return;
		}
		BashPacket packet = (BashPacket) PacketFactory.create(PacketFactory.BASH, 0);
		packet.cmd = cmd;
		packet.host = host;
		packet.port = port;
		packet.user = user;
		m_client.sendPacket(expire, packet, callback);
	}
	
	private int waitForSimple(int expire, String info, Packet packet) {
		if (m_client == null) {
			return Errno.COM_INIT_ERROR;
		}
		String name = packet.getClass().getSimpleName();
		ProxyCallback callback = new ProxyCallback();
		m_client.sendPacket(expire, packet, callback);
		AckPacket p = (AckPacket) callback.waitFor(expire);
		if (p == null) {
			Log.log("wait %s error;%s;errno=%d", name, info, callback.errno);
			return callback.errno;
		}
		if (p.errno != Errno.SUCCESS) {
			Log.log("proc %s error;%s;errno=%d;desc=%s", name, info, p.errno, p.desc);
			return p.errno;
		}
		return Errno.SUCCESS;
	}
	
	private Packet wrapHostPacket(String host, int port, String user, String password, int action) {
		long timestamp = Calendar.getInstance().getTimeInMillis();
		String cipher = FalconHost.encrypt(password, host, port, user, timestamp);
		if (cipher == null) {
			return null;
		}
		HostPacket packet = (HostPacket) PacketFactory.create(PacketFactory.HOST, 0);
		packet.action = action;
		packet.cipher = cipher;
		StringBuilder sb = new StringBuilder(256);
		sb.append('\n');
		sb.append(host);
		sb.append('\n');
		sb.append(port);
		sb.append('\n');
		sb.append(user);
		sb.append('\n');
		sb.append(timestamp);
		packet.parameter = sb.toString();
		return packet;
	}
	
	private FalconClient m_client;
}
